package com.huarui.payInvoice.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.ewaf.framework.model.ListModel;
import org.ewaf.framework.service.BaseService;
import org.ewaf.framework.util.BeanUtil;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;

import com.huarui.code.dao.ICodeGenericDao;
import com.huarui.code.model.CodeGeneric;
import com.huarui.partner.dao.IPartnerDao;
import com.huarui.partner.model.Partner;
import com.huarui.partner.service.PartnerService;
import com.huarui.payInvoice.dao.IPayInvoiceDao;
import com.huarui.payInvoice.model.PayInvoice;
import com.huarui.payInvoice.util.PayInvoiceMessageEnum;
import com.huarui.payInvoiceItem.dao.IPayInvoiceItemDao;
import com.huarui.payInvoiceItem.model.PayInvoiceItem;
import com.huarui.payable.dao.IPayableDao;
import com.huarui.payable.model.Payable;
import com.huarui.payable.service.PayableService;
import com.huarui.user.model.SessionMessage;

public class PayInvoiceService extends BaseService {
	private final static Logger logger = Logger
			.getLogger(PayInvoiceService.class);
	private ICodeGenericDao iCodeGenericDao;
	private IPayInvoiceItemDao iPayInvoiceItemDao;
	private IPayableDao iPayableDao;
	private PayableService payableService;
	private PartnerService partnerService;
	private IPartnerDao partnerDao;

	private IPayInvoiceDao getDao() {
		return (IPayInvoiceDao) dao;
	}

	@SuppressWarnings("unchecked")
	public ListModel getByCondition(ListModel lm, Map map) {
		Integer total = this.getDao().getByConditionsForCount(map);
		lm.setTotal(total);
		map.put("listModel", lm);
		List result = this.getDao().getListByConditions(map);
		lm.setResult(result);
		return lm;
	}

	@SuppressWarnings("unchecked")
	public List<Map> getListByCondition(Map map) {
		List result = this.getDao().getListByConditions(map);
		return result;
	}

	@SuppressWarnings("unchecked")
	public Map<String,Object> getPayInvoiceById(final Integer id,final SessionMessage sm) {
		List<Map> result = null;
		Map<String, Object> resultMap = new HashMap<String, Object>();
		try {
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("id", id);
			map.put("companyId", sm.getCompanyId());
			result = getListByCondition(map);
		} catch (Exception e) {
			logger.error("应付款查询出错", e);
			resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(),PayInvoiceMessageEnum.ERROR_MSG_DATABASE.getMsg());
			return resultMap;
		}
		if (result!=null&&result.size() > 0) {
			resultMap.put("data", result.get(0));
			if(result.get(0).containsKey("customerId")){
				Partner partner=(Partner) partnerService.getById(result.get(0).get("customerId"));
				partner=partnerService.getComboProperties(partner);
				resultMap.put("partner", partner);
			}
		}
		resultMapInfo(resultMap);
		return resultMap;
	}
	public Map<String,Object> createFormPayable(final String payableIds,final Integer customerId,final SessionMessage sm){
		final Map<String, Object> resultMap = new HashMap<String, Object>();
		try {
			transactionTemplate.execute(new TransactionCallback() {
				@SuppressWarnings("unchecked")
				@Override
				public Object doInTransaction(TransactionStatus status) {
					String[] strs=payableIds.split(",");
					Map map=new HashMap();
					map.put("ids", strs);
					List list=payableService.getPayableByConditions(null, map);
					resultMap.put("payableList", list);
					if(customerId!=null){
						Partner partner=(Partner) partnerService.getById(customerId);
						if(partner!=null){
							resultMap.put("partner", partner);
						}
					}
					return null;
				}
			});
		} catch (Exception e) {
			logger.error("创建付款单出错",e);
			resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(),PayInvoiceMessageEnum.ERROR_MSG_DATABASE.getMsg());
			return resultMap;
		}
		resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(),PayInvoiceMessageEnum.RESULT_TYPE_SUCCESS.getMsg());
		return resultMap;
	}

	/* 保存 */
	public Map<String,Object> savePayInvAndItems(final PayInvoice payInvoiceTemp,
			final List<PayInvoiceItem> list, final SessionMessage sm) {
		final Map<String,Object> resultMap=new HashMap<String, Object>();
		// 修改数据
		try {
			transactionTemplate.execute(new TransactionCallback() {
				@Override
				public Object doInTransaction(TransactionStatus status) {
					savePayInvoiceAndItems(payInvoiceTemp, list, sm,resultMap,status);
					return null;
				}
			});
		} catch (Exception e) {
			logger.error("保存应付款出错",e);
			resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(), PayInvoiceMessageEnum.ERROR_MSG_DATABASE.getMsg());
			return resultMap;
		}
		resultMapInfo(resultMap);
		return resultMap;
	}

	@SuppressWarnings("unchecked")
	private PayInvoice savePayInvoiceAndItems(PayInvoice payInvoiceTemp,
			List<PayInvoiceItem> list, SessionMessage sm,Map<String,Object> resultMap,TransactionStatus status) {
		Map map = new HashMap();
		PayInvoice payInvoice=null;
		if (payInvoiceTemp.getId() != null) {
			map.put("id", payInvoiceTemp.getId());
			map.put("companyId", sm.getCompanyId());
			map.put("isLock", true);
			payInvoice=(PayInvoice) getDao().getById(map);
			if(payInvoice==null){
				resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(), PayInvoiceMessageEnum.ERROR_MSG_NOTEXIST.getMsg());
				status.isRollbackOnly();
				return null;
			}else if(payInvoice.getCurrentorId().intValue()!=sm.getUserId()){
				resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(), PayInvoiceMessageEnum.ERROR_MSG_ALREADY.getMsg());
				status.isRollbackOnly();
				return null;
			}
			payInvoice.setCustomerId(payInvoiceTemp.getCustomerId());
			payInvoice.setCodeOfSeller(payInvoiceTemp.getCodeOfSeller());
			payInvoice.setGmtActualPay(payInvoiceTemp.getGmtActualPay());
			payInvoice.setInvoiceType(payInvoiceTemp.getInvoiceType());
			payInvoice.setAmount(payInvoiceTemp.getAmount());
			getDao().update(payInvoice);
		} else {
			payInvoice=new PayInvoice();
			payInvoice.setCurrentorId(sm.getUserId());
			payInvoice.setCompanyId(sm.getCompanyId());
			payInvoice.setStatus(0);
			payInvoice.setCreator(sm.getUserId());
			payInvoice.setCodeOfBuyer(iCodeGenericDao.getNewCode(sm.getCompanyId(),CodeGeneric.PAYINVOICE));
			//
			payInvoice.setCustomerId(payInvoiceTemp.getCustomerId());
			payInvoice.setCodeOfSeller(payInvoiceTemp.getCodeOfSeller());
			payInvoice.setGmtActualPay(payInvoiceTemp.getGmtActualPay());
			payInvoice.setInvoiceType(payInvoiceTemp.getInvoiceType());
			payInvoice.setAmount(payInvoiceTemp.getAmount());		
			getDao().create(payInvoice);
		}
		
		map.clear();
		map.put("payInvoiceId", payInvoice.getId());
		//iPayInvoiceItemDao.deleteByCondition(map);
		List<Map> queryList=iPayInvoiceItemDao.getPayInvoiceItemByConditions(map);
		Map<Integer,PayInvoiceItem> payInvItemMap=new HashMap<Integer, PayInvoiceItem>();
		for(Map item:queryList){
			PayInvoiceItem payInvoiceItem=new PayInvoiceItem();
			BeanUtil.populateBean(payInvoiceItem, item);
			payInvItemMap.put(payInvoiceItem.getId(), payInvoiceItem);
		}
		
		for (PayInvoiceItem invoiceItem : list) {
			if (invoiceItem.getId() == null) {
				invoiceItem.setCompanyId(sm.getCompanyId());
				invoiceItem.setPayInvoiceId(payInvoice.getId());
				iPayInvoiceItemDao.create(invoiceItem);
			} else if(invoiceItem.getId() != null){
				iPayInvoiceItemDao.update(invoiceItem);
				payInvItemMap.remove(invoiceItem.getId());
			} 
		}
		Set<Integer> removeSet= payInvItemMap.keySet();
		List<Integer> removeList=new ArrayList<Integer>();
		for(Integer id:removeSet){
			removeList.add(id);
		}
		map.clear();
		map.put("ids", removeList);
		iPayInvoiceItemDao.deleteByCondition(map);
		
		map.clear();
		map.put("payInvoiceId", payInvoice.getId());
		//iPayInvoiceItemDao.deleteByCondition(map);
		List<Map> itemList=iPayInvoiceItemDao.getPayInvoiceItemByConditions(map);
		BigDecimal amount=getPayInvoiceAmount(itemList);
		payInvoice.setAmount(amount);
		getDao().update(payInvoice);
		putSaleInvoiceResult(payInvoice.getId(),sm.getCompanyId(),resultMap);
		resultMap.put("payInvoiceItemList", itemList);
		return payInvoice;
	}
	private BigDecimal getPayInvoiceAmount(List<Map> itemList){
		BigDecimal amount=BigDecimal.ZERO;
		for(Map o:itemList){
			BigDecimal paid=(BigDecimal) o.get("paid");
			Integer documentType=(Integer) o.get("documentType");
			if(documentType!=null&&documentType==3){
				amount=amount.subtract(paid);
			}else{
				amount=amount.add(paid);
			}
		}
		return amount;
	}
	@SuppressWarnings("unchecked")
	public void putSaleInvoiceResult(Integer id,Integer companyId,Map<String,Object> resultMap){
		Map<String,Object> map=new HashMap<String, Object>();
		map.put("id", id);
		map.put("companyId", companyId);
		Map payInMap = getDao().getObjByConditions(map);
		resultMap.put("payInvoice", payInMap);
	}
	public Map<String,Object> delete(final Integer id) {
		final Map<String, Object> resultMap = new HashMap<String, Object>();
		try {
			transactionTemplate.execute(new TransactionCallback() {
				@SuppressWarnings("unchecked")
				@Override
				public Object doInTransaction(TransactionStatus status) {
					getDao().deleteById(id);
					Map map = new HashMap();
					map.put("payInvoiceId", id);
					iPayInvoiceItemDao.deleteByCondition(map);
					return null;
				}
			});
		} catch (Exception e) {
			logger.error("删除付款单出错",e);
			resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(),PayInvoiceMessageEnum.ERROR_MSG_DATABASE.getMsg());
			return resultMap;
		}
		resultMapInfo(resultMap);
		return resultMap;
	}

	public Map<String, Object> submitPayInvoice(final PayInvoice payInvoiceTemp,
			final List<PayInvoiceItem> list, final SessionMessage sm) {
		final Map<String, Object> resultMap = new HashMap<String, Object>();
		try {
			transactionTemplate.execute(new TransactionCallback() {
				@SuppressWarnings("unchecked")
				@Override
				public Object doInTransaction(TransactionStatus status) {
					PayInvoice payInvoice=savePayInvoiceAndItems(payInvoiceTemp, list, sm,resultMap,status);
					if(payInvoice!=null){
						boolean isSuccess=savePable(list,status,resultMap);
						if(!isSuccess){
							return null;
						}
						savePartner(payInvoice);
						payInvoice.setStatus(PayInvoice.STATUS_FORMAL);
						payInvoice.setPayer(sm.getUserId());
						payInvoice.setGmtPay(new Date());
						getDao().update(payInvoice);
						putSaleInvoiceResult(payInvoice.getId(),sm.getCompanyId(),resultMap);
					}
					return null;
				}
			});
		} catch (Exception e) {
			logger.error("提交付款单出错",e);
			resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(),PayInvoiceMessageEnum.ERROR_MSG_DATABASE.getMsg());
			return resultMap;
		}
		resultMapInfo(resultMap);
		return resultMap;
	}
	private void savePartner(PayInvoice payInvoice){
		Map<String,Object> map=new HashMap<String, Object>();
		//map.put("ownerId", payInvoice.getCompanyId());
		map.put("id", payInvoice.getCustomerId());
		map.put("isLock", true);
		Partner partner=partnerService.getPartnerByCondition(map);
		partner.setPaid((partner.getPaid()==null?BigDecimal.ZERO:partner.getPaid()).add(payInvoice.getAmount()==null?BigDecimal.ZERO:payInvoice.getAmount()));
		partner.setUnpaid((partner.getUnpaid()==null?BigDecimal.ZERO:partner.getUnpaid()).subtract(payInvoice.getAmount()==null?BigDecimal.ZERO:payInvoice.getAmount()));
		partnerDao.updatePartnerAmountById(partner);
	}
	public Map<String,Object> release(final Integer id,final SessionMessage sm){
		final Map<String, Object> resultMap = new HashMap<String, Object>();
		try {
			transactionTemplate.execute(new TransactionCallback() {
				@Override
				public Object doInTransaction(TransactionStatus status) {
					Map<String,Object> map=new HashMap<String,Object>();
					map.put("id",id);
					map.put("companyId", sm.getCompanyId());
					PayInvoice payInvoice=(PayInvoice) getDao().getById(map);
					if(payInvoice==null){
						resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(),PayInvoiceMessageEnum.ERROR_MSG_NOTEXIST.getMsg());
						status.isRollbackOnly();
						return null;
					}
					payInvoice.setCurrentorId(null);
					getDao().update(payInvoice);
					return null;
				}
			});
		} catch (Exception e) {
			logger.error("释放付款单出错",e);
			resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(),PayInvoiceMessageEnum.ERROR_MSG_DATABASE.getMsg());
			return resultMap;
		}
		resultMapInfo(resultMap);
		return resultMap;
	}
	public Map<String,Object> receive(final Integer id,final SessionMessage sm){
		final Map<String, Object> resultMap = new HashMap<String, Object>();
		try {
			transactionTemplate.execute(new TransactionCallback() {
				@Override
				public Object doInTransaction(TransactionStatus status) {
					Map<String,Object> map=new HashMap<String,Object>();
					map.put("id",id);
					map.put("companyId", sm.getCompanyId());
					PayInvoice payInvoice=(PayInvoice) getDao().getById(map);
					if(payInvoice==null){
						resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(),PayInvoiceMessageEnum.ERROR_MSG_NOTEXIST.getMsg());
						status.isRollbackOnly();
						return null;
					}
					payInvoice.setCurrentorId(sm.getUserId());
					getDao().update(payInvoice);
					return null;
				}
			});
		} catch (Exception e) {
			logger.error("接收付款单出错",e);
			resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(),PayInvoiceMessageEnum.ERROR_MSG_DATABASE.getMsg());
			return resultMap;
		}
		resultMapInfo(resultMap);
		return resultMap;
	}
	@SuppressWarnings("static-access")
	private boolean savePable(List<PayInvoiceItem> list,TransactionStatus status,Map<String, Object> resultMap) {
		for (PayInvoiceItem invoiceItem : list) {
			Map<String,Object> map=new HashMap<String,Object>();
			map.put("id", invoiceItem.getPayableId());
			//map.put("isLock", true);
			Payable payable = (Payable) iPayableDao.getById(map);
			if(payable.getPayable().subtract(payable.getPaid()).compareTo(invoiceItem.getPaid())<0){
				resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(),PayInvoiceMessageEnum.ERROR_MSG_ALMODIFY.getMsg());
				status.isRollbackOnly();
				return false;
			}
			if(payable.getPaid()!=null&&invoiceItem.getPaid()!=null){
				payable.setPaid(payable.getPaid().add(invoiceItem.getPaid()));
			}
			if (payable.getPayable().compareTo(payable.getPaid()) == 0) {
				payable.setStatus(payable.STATUS_COMPLETE);
			}
			iPayableDao.update(payable);
		}
		return true;
	}
	private void resultMapInfo(Map<String,Object> resultMap){
		if(!resultMap.containsKey(PayInvoiceMessageEnum.SUCCESS.getMsg())){
			resultMap.put(PayInvoiceMessageEnum.SUCCESS.getMsg(),PayInvoiceMessageEnum.RESULT_TYPE_SUCCESS.getMsg());
		}
	}
	public ICodeGenericDao getiCodeGenericDao() {
		return iCodeGenericDao;
	}

	public void setiCodeGenericDao(ICodeGenericDao iCodeGenericDao) {
		this.iCodeGenericDao = iCodeGenericDao;
	}

	public IPayInvoiceItemDao getiPayInvoiceItemDao() {
		return iPayInvoiceItemDao;
	}

	public void setiPayInvoiceItemDao(IPayInvoiceItemDao iPayInvoiceItemDao) {
		this.iPayInvoiceItemDao = iPayInvoiceItemDao;
	}

	public IPayableDao getiPayableDao() {
		return iPayableDao;
	}

	public void setiPayableDao(IPayableDao iPayableDao) {
		this.iPayableDao = iPayableDao;
	}

	public void setPayableService(PayableService payableService) {
		this.payableService = payableService;
	}

	public void setPartnerService(PartnerService partnerService) {
		this.partnerService = partnerService;
	}

	public void setPartnerDao(IPartnerDao partnerDao) {
		this.partnerDao = partnerDao;
	}

}
